package dons;

import java.util.ArrayList;

import classes.EClasses;

import data.De;
import data.ECaracteristique;

public class ListeDons {

	private Don liste[];
	private EDons partListeGeneral[];
	private EDons partListeMagie[];
	private EDons partListeGuerrier[];
	private EDons partListeGuerrierCC[];
	private EDons partListeGuerrierDistance[];
	private EDons partListeGuerrierMonte[];
	
	private int caracteristiques[];
	
	public ListeDons (int caracteristiques[]) {
		initialisationListe ();
		initialisationDons ();
		
		this.caracteristiques = caracteristiques;
	}
	
	private void initialisationListe () {
		liste = new Don[EDons.values().length];
		
		partListeGeneral = new EDons[4];
		partListeGeneral[0] = EDons.Athletisme;
		partListeGeneral[1] = EDons.Esquive;
		partListeGeneral[2] = EDons.Souplesse_du_serpent;
		partListeGeneral[3] = EDons.Voltigeur;
		
		partListeMagie = new EDons[2];
		partListeMagie[0] = EDons.Affinite_magique;
		partListeMagie[1] = EDons.Science_du_renvoi;
		
		partListeGuerrier = new EDons[2];
		partListeGuerrier[0] = EDons.Arme_de_predilection;
		partListeGuerrier[1] = EDons.Specialisation_martiale_superieure;
		
		partListeGuerrierCC = new EDons[2];
		partListeGuerrierCC[0] = EDons.Attaque_eclair;
		partListeGuerrierCC[1] = EDons.Succession_d_enchainements;
		
		partListeGuerrierDistance = new EDons[2];
		partListeGuerrierDistance[0] = EDons.Feu_nourri;
		partListeGuerrierDistance[1] = EDons.Tir_rapide;
		
		partListeGuerrierMonte = new EDons[2];
		partListeGuerrierMonte[0] = EDons.Attaque_au_galop;
		partListeGuerrierMonte[1] = EDons.Pietinement;
	}
	
	//TODO enlever cas null quand tous les dons seront implémentés
	private void initialisationDons () {
		for (EDons d : EDons.values()) {
			try {
				liste[d.ordinal()] = (Don) Class.forName("dons."+d).newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				liste[d.ordinal()] = null;
				//System.out.println(d + " not found");
			}
		}
	}
	
	//TODO enlever cas null quand tous les dons seront implémentés
	public ArrayList<EDons> getDonsDispo (int bba, EClasses classe) {
		ArrayList<EDons> donsDispo = new ArrayList<EDons> ();
		
		for (EDons d : EDons.values()) {
			Don don = liste[d.ordinal()];
			
			if (don != null) {
				if ((don.getBbaNecessaire() <= bba)
						&& ((don.getClasseNecessaire() == null) || (don.getClasseNecessaire().equals(classe)))
						&& (don.getDexNecessaire() <= caracteristiques[ECaracteristique.DEX.ordinal()])
						&& (don.estPrenable())
						&& ((!don.estPris()) || (don.estMultiple()))) {
					if (aDons (don.getDonsNecessaires())) {
						donsDispo.add(d);
					}
				}
			}
		}
		
		return donsDispo;
	}
	
	//TODO enlever cas null quand tous les dons seront implémentés
	private boolean aDons (ArrayList<EDons> dons) {
		if (dons != null) { //S'il est null, il n'y a pas de dons necessaire, donc true
			for (EDons d : dons) {
				if (liste[d.ordinal()] == null) //enleve celui-ci
					return false;
				else {
					if (!liste[d.ordinal()].estPris())
						return false;
				}
			}
		}
		return true;
	}
	
	private EDons[] getPartListe (ETypesDons typeDonsVoulu) {
		EDons tabRetour[];
		
		//Concaténation des différentes parties possible suivant le type voulu
		switch (typeDonsVoulu) {
		case General:
			return partListeGeneral;
		case Magie:
			tabRetour = new EDons[partListeGeneral.length + partListeMagie.length];
			System.arraycopy(partListeGeneral, 0, tabRetour, 0, partListeGeneral.length);
	        System.arraycopy(partListeMagie, 0, tabRetour, partListeGeneral.length, partListeMagie.length);
			return tabRetour;
		case Guerrier:
			tabRetour = new EDons[partListeGeneral.length + partListeGuerrier.length];
			System.arraycopy(partListeGeneral, 0, tabRetour, 0, partListeGeneral.length);
	        System.arraycopy(partListeGuerrier, 0, tabRetour, partListeGeneral.length, partListeGuerrier.length);
			return tabRetour;
		case GuerrierCC:
			tabRetour = new EDons[partListeGeneral.length + partListeGuerrier.length + partListeGuerrierCC.length];
			System.arraycopy(partListeGeneral, 0, tabRetour, 0, partListeGeneral.length);
	        System.arraycopy(partListeGuerrier, 0, tabRetour, partListeGeneral.length, partListeGuerrier.length);
	        System.arraycopy(partListeGuerrierCC, 0, tabRetour, partListeGeneral.length + partListeGuerrier.length, partListeGuerrierCC.length);
			return tabRetour;
		case GuerrierDistance:
			tabRetour = new EDons[partListeGeneral.length + partListeGuerrier.length + partListeGuerrierDistance.length];
			System.arraycopy(partListeGeneral, 0, tabRetour, 0, partListeGeneral.length);
	        System.arraycopy(partListeGuerrier, 0, tabRetour, partListeGeneral.length, partListeGuerrier.length);
	        System.arraycopy(partListeGuerrierDistance, 0, tabRetour, partListeGeneral.length + partListeGuerrier.length, partListeGuerrierDistance.length);
			return tabRetour;
		case GuerrierMonte :
			tabRetour = new EDons[partListeGeneral.length + partListeGuerrier.length + partListeGuerrierMonte.length];
			System.arraycopy(partListeGeneral, 0, tabRetour, 0, partListeGeneral.length);
	        System.arraycopy(partListeGuerrier, 0, tabRetour, partListeGeneral.length, partListeGuerrier.length);
	        System.arraycopy(partListeGuerrierMonte, 0, tabRetour, partListeGeneral.length + partListeGuerrier.length, partListeGuerrierMonte.length);
			return tabRetour;
		}
		
		return partListeGeneral;
	}

	//Rajout d'un don choisi au préalable
	public boolean addDon (EDons donARajouter, int bba, EClasses classe) {
		if (getDonsDispo(bba, classe).contains(donARajouter)) {
			return liste[donARajouter.ordinal()].prends(null, null);
		}
		else
			return false;
	}

	//Rajout d'un don choisi au hasard dans la liste voulue
	public boolean addDon (ETypesDons typeDonARajouter, int bba, EClasses classe) {
		ArrayList<EDons> listeDonsDispo = getDonsDispo(bba, classe);
		ArrayList<EDons> donsPossible = new ArrayList<EDons>();
		
		//On choisi dans la liste voulue
		for (EDons don : getPartListe(typeDonARajouter)) {
			if (listeDonsDispo.contains(don)) {
				donsPossible.add(don);
			}
		}
		
		EDons donTire = donsPossible.get(De.lancer(donsPossible.size())-1);
		
		
		
		return liste[donTire.ordinal()].prends(null, null);
	}

	//Rajout d'un don non prenable (cas d'un don de changement de niveau d'une classe particuliere)
	public boolean addDon (EDons donARajouter) {
		if (!liste[donARajouter.ordinal()].estPrenable()) {
			return liste[donARajouter.ordinal()].prends(null, null);
		}
		else
			return false;
	}
	
	@Override
 	public String toString() {
		String retour = "Liste des dons :\n";
		
		for (Don d : liste) {
			if (d != null) {
				if (d.estPris())
					retour += d + "\n";
			}
		}
		
		return retour;
	}
}
